package com.fortune.cat.filter.factory;

import com.fortune.cat.bean.DegradeConfig;
import com.fortune.cat.utils.ServerResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Objects;

import static com.fortune.cat.constant.DegradeConstants.*;

/**
 * @author zhaozeyang
 * @date 2019/4/23 14:22
 * @description 默认的降级过滤器
 */
@Slf4j
@Component
public class DefaultDowngradeFilterFactory extends AbstractCustomizeGatewayFilterFactory<DegradeConfig> {


    private static AntPathMatcher antPathMatcher = new AntPathMatcher();

    public DefaultDowngradeFilterFactory() {
        super(DegradeConfig.class);
    }

    @Override
    protected Mono<Void> doApply(DegradeConfig config, ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("DefaultDowngradeFilterFactory | config is {}", config);
        //先查看path和method是否匹配
        List<DegradeConfig.DegradeInfo> degradeInfoList = config.getDegradeInfoList();
        if (CollectionUtils.isEmpty(degradeInfoList)) {
            return chain.filter(exchange);
        }
        String path = exchange.getRequest().getPath().value();
        String method = exchange.getRequest().getMethod().name();
        DegradeConfig.ReturnInfo returnInfo = null;
        for (DegradeConfig.DegradeInfo degradeInfo : degradeInfoList) {
            Integer degradeType = degradeInfo.getDegradeType();
            if (!method.equalsIgnoreCase(degradeInfo.getMethod()) || !antPathMatcher.match(degradeInfo.getPath(), path)) {
                continue;
            }
            if (DEGRADE_TYPE_ONLY_PATH.equals(degradeType)) {
                //匹配到path
                returnInfo = degradeInfo.getCommonReturnInfo();
            }
            if (DEGRADE_TYPE_PATH_QUERY.equals(degradeType)) {
                returnInfo = matchQuery(exchange.getRequest(), degradeInfo.getQueryInfo());
            }
            if (DEGRADE_TYPE_PATH_HEADER.equals(degradeType)) {
                returnInfo = matchHeader(exchange.getRequest(), degradeInfo.getHeaderInfo());
            }
            if (Objects.nonNull(returnInfo)) {
                break;
            }
        }
        log.info("DefaultDowngradeFilterFactory | returnInfo is {}", returnInfo);
        if (Objects.nonNull(returnInfo)) {
            return ServerResponseUtils.ReturnCommonResponse(returnInfo, exchange);
        }
        return chain.filter(exchange);
    }

    private DegradeConfig.ReturnInfo matchHeader(ServerHttpRequest request, List<DegradeConfig.HeaderInfo> headerInfoList) {
        for (DegradeConfig.HeaderInfo headerInfo : headerInfoList) {
            if (!headerInfo.getHeaderValue().equals(request.getHeaders().getFirst(headerInfo.getHeaderValue()))) {
                continue;
            }
            return headerInfo.getReturnInfo();
        }
        return null;
    }

    private DegradeConfig.ReturnInfo matchQuery(ServerHttpRequest request, List<DegradeConfig.QueryInfo> queryInfoList) {
        for (DegradeConfig.QueryInfo queryInfo : queryInfoList) {
            if (!queryInfo.getQueryValue().equals(request.getQueryParams().getFirst(queryInfo.getQueryName()))) {
                continue;
            }
            return queryInfo.getReturnInfo();
        }
        return null;
    }

    @Override
    protected int doGetOrder() {
        return 0;
    }

    @Override
    protected boolean skipPresent(DegradeConfig degradeConfig, ServerWebExchange exchange) {
        return false;
    }
}
